import usePermission from '@/hooks/usePermission'
import type { Respond } from '@/types'
import { isHttp } from '@/utils/validate'
import useNetwork from '@/hooks/useNetwork'
import { urlFormat } from '@/utils/strings'

const isPhpService = import.meta.env.VITE_APP_SERVICE_LANG === 'php'

function toPhpQuery (obj: string | AnyObject | ArrayBuffer | undefined) {
  if (!obj) return ''
  if (typeof obj !== 'object' || Array.isArray(obj) || obj instanceof ArrayBuffer) return obj

  const permission = usePermission()
  if (!obj.token && permission.token) obj.token = permission.token

  const arr: string[] = []
  Object.entries(obj).forEach(([k, v]) => {
    if (v !== undefined && v !== null) {
      if (k === 'params' || k === 'pageinfo') {
        if (typeof v === 'object') {
          Object.entries(v).forEach(([sk, sv]) => {
            if (sv !== undefined && sv !== null) {
              arr.push(`${k}[${sk}]=${encodeURIComponent(sv as any)}`)
            }
          })
        }
      } else if (typeof v === 'object' || Array.isArray(v)) {
        arr.push(`params[${k}]=${encodeURIComponent(JSON.stringify(v))}`)
      } else {
        arr.push(`params[${k}]=${encodeURIComponent(obj[k])}`)
      }
    }
  })
  return arr.join('&')
}

/**
 * 递归去除对象中值为 null 的字段
 */
function removeNull(obj: any): any {
  if (Array.isArray(obj)) {
    return obj.map(removeNull)
  } else if (obj && typeof obj === 'object' && !(obj instanceof ArrayBuffer)) {
    const newObj: any = {}
    Object.entries(obj).forEach(([k, v]) => {
      if (v !== null) {
        newObj[k] = removeNull(v)
      }
    })
    return newObj
  }
  return obj
}

/**
 * 接口请求
 * @param options { hideToast: '是否隐藏失败提示' }
 */
async function request<T = Record<string, any>, R = Respond<T>> (options: Parameters<typeof uni.request>[0] & { hideToast?: boolean }) {
  return new Promise<R>((resolve, reject) => {
    const permission = usePermission()
    const network = useNetwork()
    if (!network.isConnected) {
      if (!options.hideToast) {
        uni.showToast({
          icon: 'error',
          title: '无网络连接',
        }).then()
      }
      reject('无网络连接')
    }
    // 过滤掉 data 中为 null 的字段
    const filteredData = options.data ? removeNull(options.data) : options.data
    const baseUrl = import.meta.env.VITE_APP_BASE_API
    uni.request({
      ...options,
      url: isHttp(options.url) ? options.url : `${baseUrl}${options.url}`,
      method: options.method ?? 'POST',
      // data: isPhpService ? toPhpQuery(options.data) : options.data,
      data: isPhpService ? toPhpQuery(filteredData) : filteredData,
      timeout: options.timeout || 10000,
      header: {
        'Content-Type': 'application/json',
        ...options.header,
        Authorization: options.header?.Authorization ?? (permission.token && !isPhpService ? `Bearer ${permission.token}` : ''),
        'x-access-token': permission.token || '',
        'Tenant-Id': permission.tenantId || '',
        'Region-Header': permission.regionHeader || '',
        cookie: uni.getStorageSync('cookie') || '',
      },
      success: (response) => {
        const res: any = response.data
        const cookie = /nlf_front_session=([^;]+)/g.exec(response.header['Set-Cookie'] || '')?.[0]
        if (cookie && !isHttp(options.url)) {
          uni.setStorage({
            key: 'cookie',
            data: cookie,
          })
        }

        if (res instanceof ArrayBuffer || (options.responseType && options.responseType !== 'json')) {
          resolve(res)
          return
        }

        const code = Number(res.code)
        if ((res.success !== undefined && res.success) || code === 0 || code === 200 || code === 100000 || code === 300||code === 400||code === 500) {
          resolve(res)
        } else if (code === 401 || code === 1005) {
          /*
          permission.logout().finally(() => {
            uni.reLaunch({ url: '/pages/login/index' }).then()
          })
            */
           uni.reLaunch({ url: '/pages/login/index' }).then()
          reject(401)
        } else {
          if (!options.hideToast) {
            uni.showToast({
              icon: 'none',
              title: res.msg || res.message || '接口未知错误',
            }).then()
          }
          reject(response)
        }
      },
      fail: (reason) => {
        if (!options.hideToast) {
          uni.showToast({
            icon: 'none',
            title: '服务器错误',
          }).then()
        }
        console.error(reason)
        reject(reason)
      },
    })
  })
}

/**
 * 下载文件到临时目录
 * @param options
 */
export async function download (options: Parameters<typeof uni.downloadFile>[0]) {
  const permission = usePermission()

  const baseUrl = import.meta.env.VITE_APP_BASE_API

  return new Promise<string>((resolve, reject) => {
    uni.downloadFile({
      url: isHttp(options.url) ? options.url : `${baseUrl}${options.url}`,
      timeout: options.timeout || 60000,
      header: {
        ...options.header,
        Authorization: options.header?.Authorization ?? (permission.token ? `Bearer ${permission.token}` : ''),
      },
      success: (response) => {
        resolve(response.tempFilePath)
      },
      fail: (reason) => {
        reject(reason)
      },
    })
  })
}

/**
 * 上传接口，参传参数 filePath(单文件上传)  或 files(多文件上传)
 * @param options
 */
export async function upload (options: Omit<Parameters<typeof uni.uploadFile>[0], 'url'> & { url?: string }) {
  const permission = usePermission()

  const baseUrl = import.meta.env.VITE_APP_BASE_API
  const uploadUrl = import.meta.env.VITE_APP_UPLOAD_API

  return new Promise<Record<string, any>>((resolve, reject) => {
    uni.uploadFile({
      ...options,
      name: options.name ?? 'file',
      url: options.url && isHttp(options.url) ? options.url : urlFormat(`${baseUrl}/${options.url || uploadUrl}`),
      timeout: options.timeout || 60000,
      header: {
        ...options.header,
        Authorization: options.header?.Authorization ?? (permission.token ? `Bearer ${permission.token}` : ''),
      },
      success (result) {
        if (result.statusCode !== 200 || !result.data) reject('服务器错误')
        const res = JSON.parse(result.data)
        const code = Number(res.code)
        if ((res.success !== undefined && res.success) || code === 0 || code === 200 || code === 100000) {
          resolve({
            ...res,
            data: typeof res.data === 'string' ? { fileName: res.data } : res.data,
          })
        } else {
          reject(res)
        }
      },
      fail (reason) {
        reject(reason)
      },
    })
  })
}

/**
 * 分页转换成服务器的格式
 * @param pageable
 */
export function toPageInfo (pageable: { page: number, size: number }) {
  const { page, size } = pageable
  if (isPhpService) {
    return {
      page,
      perpage: size,
    }
  }
  return {
    pageSize: size,
    pageNum: page,
  }
}

export default request
